import cgi
import urllib

from google.appengine.api import users
from google.appengine.ext import db

import webapp2
import random


class game(db.Model):
    game_id = db.IntegerProperty()
    player1_id = db.IntegerProperty()
    player2_id = db.IntegerProperty
    player1_ships = None #Not sure how to store ships
    player2_ships = None #Not sure how to store ships
    player1_hits = None  #Not sure how to store this
    player1_misses = None  #Not sure how to store this

#This class is meant to represent a player of the game
class Player:
    #This is the constructor for a player
    def __init__(self,id,name,player_field,hit_field):
        self.player_name = name
        self.player_field = player_field
        self.hit_field = hit_field
        self.your_turn = False
        self.player_id = id
    #Returns a 2D array containing this users ship locations 
    def getPlayerField(self):
        return self.player_field
    
    #Arguemnts: x (integer) as x coordinate, y (integer as y coordinate)
    #Description: calls a method on the opponents field and performs a "hit" at the given x,y arguments
    #Returns: False (boolean) if the x,y arguments are out of range (need to be with the 10X10 grid)
    def performHit(self,x,y):
        mark = None
        if x > 10 or y > 10 or x < 0 or y < 0:
            return False
        else:
            hit = self.opponent.getPlayerField().hitAt(x,y)
            if hit:
                mark = 'X'
                print "hit!"
            else:
                mark = 'O'
                print "miss!"
            self.hit_field.markHitField(x,y,mark) #hit_field is marked with either an X or O (hit or miss)
            
    #Setter method for setting the opponent
    def setOpponent(self,opponent):
        self.opponent = opponent
        
    #Returns: Name of player (String)
    def getName(self):
        return self.player_name

#Not sure if this is really needed, but for now it just represents the "hits" that a player made on a (10X10 grid)
class HitField:  
    
    #Constructor build a 10X10 grid and initializes all elements to 0
    def __init__(self):
        self.hit_field = [[0 for i in xrange(11)] for i in xrange(11)]
    
    #Arguemnts: x (integer) as x coordinate, y (integer as y coordinate),mark(Character)
    #Description: Marks field with character 'mark' at given 'x' and 'y' coordinates on the 10X10 grid (hit_field)
    def markHitField(self,x,y,mark):
        self.hit_field[x][y] = mark

#This class represents a 2D 10X10 Array which contains the placement of all users ships and game methods
class PlayerField:
    #Constructor requires objects of all ships(which means there coordinates too) before initialization occurs
    #Initializes 2D 10X10 array with all 0 but this occurs before the ships are placed
    def __init__(self,battleship,aircraft,destroyer,submarine,patrol):
        self.player_field = [[0 for i in xrange(11)] for i in xrange(11)] #10X10 array containing ships and positions
        self.shipsOnField = [] #List contains current ships on field
        
        #Checks each ship to make sure its placement is valid
        if self.validPlacement(battleship)and self.validPlacement(aircraft)and self.validPlacement(destroyer) and self.validPlacement(submarine) and self.validPlacement(patrol):
            #Ships are placed
            self.placeShip(battleship)
            self.placeShip(aircraft)
            self.placeShip(destroyer)
            self.placeShip(submarine)
            self.placeShip(patrol)
            #List of ships is updated with all ships
            self.shipsOnField.append(battleship)
            self.shipsOnField.append(aircraft)
            self.shipsOnField.append(destroyer)
            self.shipsOnField.append(submarine)
            self.shipsOnField.append(patrol)
            
            #with this being true, we know that all the ships were placed and this player is ready
            self.goodToGo = True
        else:    
            #game will not start since ships have been placed invalidly  
            print "some pieces have been placed incorrectly"
            self.goodToGo = False
    
    #Arguments: ship (Ship object) ship to check placement of
    #Description: This method checks the validity of the ships placement
    def validPlacement(self,ship):
        hx = ship.getHeadX; #the X coordinate of the head of the ship 
        hy = ship.getHeadY; #the Y coordinate of the head of the ship 
        tx = ship.getTailX; #the X coordinate of the tail of the ship 
        ty = ship.getTailY; #the Y coordinate of the tail of the ship 
        
        
        if not hx > 0 and not hx < 11: #Makes sure head X coordinate is valid
            return False
        if not hy > 0 and not hy < 11: #Makes sure head Y coordinate is valid
            return False
        if not tx > 0 and not tx < 11: #Makes sure tail X coordinate is valid
            return False
        if not ty > 0 and not ty < 11: #Makes sure tail Y coordinate is valid
            return False
        return True #None of negative checks were found to be true
    
    #Arguments: ship_obj(Ship Object) ship to be placed on field
    #Description: Takes a ship object and places the ship object on the playerField  
    def placeShip(self,ship_obj):
        hx = ship_obj.getHeadX(); #Refer to comments above
        hy = ship_obj.getHeadY();
        tx = ship_obj.getTailX();
        ty = ship_obj.getTailY();
        iyr = 0 #Range of spaces ship will occupy vertically
        ixr = 0 #Range of spaces ship will occupy horizontally
        
        if hy==ty: #If ship lies horizontally
            if hx-tx > 0:
                ixr = range(0,(hx+1)-tx) #Represents range of spaces the ship will occupy (positive direction)
            else:
                ixr = range(hx-(tx+1),0) #Represents range of spaces the ship will occupy (negative direction)
            for i in ixr:                #For every space that the ship takes up on 10X10 grid
                self.player_field[abs(hx+i)+1][hy]=ship_obj.getShipID() #Set the value of ship location to the ship's ID
        elif hx==tx: #If ship lies vertically
            if hy-ty > 0:
                iyr = range(0,(hy+1)-ty) #Refer to comments above
            else:
                iyr = range(hy-(ty+1),0)#Refer to comments above
            for i in iyr:
                self.player_field[hx][abs(hy+i)+1]=ship_obj.getShipID()#Refer to comments above
        
    #Arguments: ID (Integer) id of ship
    #Description: Takes an ID and searches all the players ships for a ship that has the ID
    #Returns: ship (Ship Object) with same id as Argument
    def getShipByID(self,ID):
        for ship in self.shipsOnField: #Checks ID for every ship on this field
            if ship.getShipID() == ID:  
                return ship 
            
    #Arguments: x (Integer), y (Integer) coordinate of desired "hit"
    #Description: Receive a hit from the opponent at 'x','y', removes ship health if hit, and marks field with a 0 if hit 
    #Returns: True (Boolean
    def hitAt(self,x,y):
        hitPos = self.player_field[x][y]
        if not hitPos == 0: #If hitPos is not 0, then there is a ship at 'x','y' (if it's not 0 then it will be the ship ID 
            self.getShipByID(hitPos).removeHealth() #Remove 1 health point from ship with the ID found at 'x','y'(player_field[x][y])
            self.player_field[x][y] = 0             #Now set to 0 so this ship will not be hit again at this spot
            return True                             #Return true that we have hit a ship
    
    #Returns: Player Field Getter (2D 10X10 array) 
    def getField(self):
        return self.player_field
    
    #Returns: List of ships on field
    def getShipsOnField(self):
        return self.shipsOnField
    
    #Arguments: ship_obj (Ship Object) ship to remove from field
    #Description: Removes the argument 'ship' literally ship object from the list of ships
    def removeShipFromField(self,ship_obj):
        self.shipsOnField.remove(ship_obj)
      
#Represents all ships... This acts as a parent class to the other ships            
class Ship(object):
    #Constructor for ship needs, ship ID(Integer), name of ship (String), health points, head x coord, head y coord, tail x coord, and tail y coord
    def __init__(self,id,name,max,hx,hy,tx,ty):
        self.ship_id = id
        self.max_health = max
        self.remaining_health = max
        self.ship_name = name
        self.head_pos_x = hx
        self.head_pos_y = hy
        self.tail_pos_x = tx
        self.tail_pos_y = ty

    #Removes one health point from ship when called
    def removeHealth(self):
        self.remaining_health -= 1
    
    #Getters Below
    def getHeadX(self):
        return self.head_pos_x
    
    def getHeadY(self):
        return self.head_pos_y
    
    def getTailX(self):
        return self.tail_pos_x
    
    def getTailY(self):
        return self.tail_pos_y
    
    def getRemainingHealth(self):
        return self.remaining_health
    
    def getShipID(self):
        return self.ship_id
    
    def getName(self):
        return self.ship_name

#Specific ship types, children of class Ship via inheritance
class Battleship(Ship):
    def __init__(self,hx,hy,tx,ty):
        Ship.__init__(self,1,"Battle Ship",4,hx,hy,tx,ty) #Passes parameters to the Ship constructor

class AircraftCarrier(Ship):
    def __init__(self,hx,hy,tx,ty):
        Ship.__init__(self,2,"Aircraft Carrier",5,hx,hy,tx,ty)

class Destroyer(Ship):
    def __init__(self,hx,hy,tx,ty):
        Ship.__init__(self,3,"Destroyer",3,hx,hy,tx,ty)

class Submarine(Ship):
    def __init__(self,hx,hy,tx,ty):
        Ship.__init__(self,4,"Submarine",3,hx,hy,tx,ty)

class PatrolBoat(Ship):
    def __init__(self,hx,hy,tx,ty):
        Ship.__init__(self,5,"Patrol Boat",2,hx,hy,tx,ty)

#This Class brings all the pieces of the game together 
class BattleshipGame:
    
    #Picks random player for first turn
    def firstTurn(self):
        rand = random.randint(1,2) 
        if rand==1:
            return self.player1
        else:
            return self.player2
    
    #Prints player 1's board (used for debugging)
    def printP1GameBoard(self):
        print self.player1_field.getField() 
    
    #Prints player 2's board (used for debugging)    
    def printP2GameBoard(self):
        print self.player1_field.getField()
        
    #Returns: Player whose turn it is (Player)
    def getCurrentPlayer(self):
        return self.current_turn
    
    #Sets the current player to the next player
    def nextTurn(self):
        if self.current_turn == self.player1:
            self.current_turn = self.player2
        else:
            self.current_turn = self.player1
            
    #Returns winner of game    
    def getWinner(self):
        winner = None
        if len(self.player1.getPlayerField().getShipsOnField()) == 0:
            winner = self.player2
            print "player 2 wins!!!"
        elif len(self.player2.getPlayerField().getShipsOnField()) == 0:
            print "player 1 wins!!!"
            winner = self.player1
        return winner
    
    #Removes dead ships from both player fields  
    def removeDeadShips(self):
        for ship_obj in self.player1_field.getShipsOnField():
            if ship_obj.getRemainingHealth() == 0:
                self.player1_field.removeShipFromField(ship_obj)
                print "you sunk a " + ship_obj.getName()
        for ship_obj in self.player2_field.getShipsOnField():
            if ship_obj.getRemainingHealth() == 0:
                self.player2_field.removeShipFromField(ship_obj)
                print "you sunk a " + ship_obj.getName()
                
    #Constructor take game id (integer),player 1 name (String) coordinates of all player 1 ships (head and tail),and same information for player 2            
    def __init__(self,game_id,p1name,p1bshx,p1bshy,p1bstx,p1bsty
                    ,p1achx,p1achy,p1actx,p1acty
                    ,p1dhx,p1dhy,p1dtx,p1dty
                    ,p1shx,p1shy,p1stx,p1sty
                    ,p1pbhx,p1pbhy,p1pbtx,p1pbty
                    
                    ,p2name,p2bshx,p2bshy,p2bstx,p2bsty
                    ,p2achx,p2achy,p2actx,p2acty
                    ,p2dhx,p2dhy,p2dtx,p2dty
                    ,p2shx,p2shy,p2stx,p2sty
                    ,p2pbhx,p2pbhy,p2pbtx,p2pbty):
        
        #Creates each player field and initializes the field with all the ships and their coordinates
        self.player1_field = PlayerField(Battleship(p1bshx,p1bshy,p1bstx,p1bsty),
                                    AircraftCarrier(p1achx,p1achy,p1actx,p1acty),
                                    Destroyer(p1dhx,p1dhy,p1dtx,p1dty),
                                    Submarine(p1shx,p1shy,p1stx,p1sty),
                                    PatrolBoat(p1pbhx,p1pbhy,p1pbtx,p1pbty))
        
        self.player2_field = PlayerField(Battleship(p2bshx,p2bshy,p2bstx,p2bsty),
                                    AircraftCarrier(p2achx,p2achy,p2actx,p2acty),
                                    Destroyer(p2dhx,p2dhy,p2dtx,p2dty),
                                    Submarine(p2shx,p2shy,p2stx,p2sty),
                                    PatrolBoat(p2pbhx,p2pbhy,p2pbtx,p2pbty))

        #Initializes both players and sets them to play each other
        self.player1 = Player(1,p1name,self.player1_field,HitField())
        self.player2 = Player(2,p2name,self.player2_field,HitField())
        self.player1.setOpponent(self.player2)
        self.player2.setOpponent(self.player1)
        
        self.current_turn = self.firstTurn() #Randomly chooses either player 1 or player 2 to go for the first turn of the game
        
#This constructor takes players names, game_id, and all the coordinates of the tail and head of every ship for both players
battleship = BattleshipGame(1,"Player1",1,1,4,1,1,2,5,2,1,3,3,3,1,4,3,4,1,5,2,5,"Player2",1,1,4,1,1,2,5,2,1,3,3,3,1,4,3,4,1,5,2,5)

while battleship.getWinner()== None: #Game loop... While there is no winner
    print battleship.getCurrentPlayer().getName() #Print Current players name
    x=input('X:')
    y=input('Y:')
    if battleship.getCurrentPlayer().performHit(x,y) != False: #If the inputed x and y coordinates are bad
        battleship.removeDeadShips()
        battleship.nextTurn()
    else:
        print "Bad Move"
#battleship.nextTurn()

